
import sys
from dslc.core.dslc_parser import UnaryOp, BinaryOp, BlockOp, Number, Identifier, String
from dslc import build_default_lexer, build_default_parser, build_default_symtab, ccode_gen
from dslc import print_ast, evaluation, fsave_ast
from dslc.passes import flatten_nested_binary_comma
from dslc.passes import merge_block_content, merge_loop_cond_pass
from dslc.passes import traversal_ast_to, flatten_loop_block
from dslc.passes import traversal_ast_to, macro_define_pass, is_macro_define_block, is_macro_expand_block, macro_expand_pass, merge_marco_param_pass
from dslc.passes import meta_pystr_in_node
from dslc.passes import builtin_macro_pass, builtin_insta_pass
from dslc.passes import merge_var_name_pass, is_var_define_block, unary_var_define_pass

def main():
    '''测试c code gen'''
    ast = open(sys.argv[1], encoding='UTF8').read()
    print(ast)

    lexer = build_default_lexer()
    tokens = lexer.tokenize(ast)
    with open('tmp/tks.c', 'w', encoding="UTF8") as fil:
        fil.write(str(tokens))

    parser = build_default_parser(tokens)
    ast = parser.parse()

    stab = build_default_symtab()

    ast = BlockOp([op for op in ast.oplist if isinstance(op, BlockOp)])

    ast = traversal_ast_to(stab, ast,\
        lambda _, x: isinstance(x, BinaryOp) and x.op == ',', flatten_nested_binary_comma)
    #fsave_ast(open("tmp/init.c", "w"), ast)
    fsave_ast(open("tmp/init.c", "w"), ast)
    #将变量处理进stab的evaluation还没有做
    #ast = merge_block_content(ast, merge_var_name_pass)
    #ast = traversal_ast_to(stab, ast,\
    #    lambda _, x: is_var_define_block(x), unary_var_define_pass)
    #fsave_ast(open("tmp/var_defined.c", "w"), ast)
    
    time_to_fix_point = 5

    for fidx in range(time_to_fix_point):

        ast = merge_block_content(ast, merge_loop_cond_pass)

        ast = evaluation(stab, ast)
        fsave_ast(open(f"tmp/eval_in_fix{fidx}.c", "w"), ast)

        traversal_ast_to(stab, ast,\
            lambda s, x: isinstance(x, BinaryOp)\
                and x.op == '!', builtin_insta_pass)
        fsave_ast(open(f"tmp/builtin_insta{fidx}.c", "w"), ast)

        #在循环展开前，许多数值都没有有效的eval，所以很多的操作要在循环展开后操作
        ast = traversal_ast_to(stab, ast,\
            lambda s, x: isinstance(x, BlockOp)\
                and len(x.oplist)>1 and isinstance(x.oplist[0], Identifier) and\
                x.oplist[0].name == 'for', flatten_loop_block)
        fsave_ast(open(f"tmp/flatten_loop{fidx}.c", "w"), ast)

        traversal_ast_to(stab, ast,\
            lambda s, x: isinstance(x, BinaryOp)\
                and x.op == '!', builtin_macro_pass)
        fsave_ast(open(f"tmp/builtin_macro{fidx}.c", "w"), ast)

    ast = evaluation(stab, ast)
    fsave_ast(open("tmp/eval_after_fix.c", "w"), ast)

    #需要evaluation先把数组取值$等op处理了才能确认某些参数
    ast = traversal_ast_to(stab, ast,\
        lambda s, x: isinstance(x, String) and isinstance(x.parent, BinaryOp), meta_pystr_in_node)
    fsave_ast(open("tmp/evmeta.c", "w"), ast)

    ast = traversal_ast_to(stab, ast,\
        lambda s, x: is_macro_define_block(x), macro_define_pass)
    fsave_ast(open("tmp/after_macro_define.c", "w"), ast)

    ast = merge_block_content(ast, merge_marco_param_pass)

    ast = traversal_ast_to(stab, ast,\
        lambda s, x: is_macro_expand_block(x), macro_expand_pass)

    fsave_ast(open("tmp/maexp.c", "w"), ast)
    with open("tmp/stab.c", "w") as fil:
        fil.write(str(stab))

    ast = evaluation(stab, ast)
    fsave_ast(open("tmp/eval_before_gen.c", "w"), ast)

    print(stab)
    cres = ccode_gen(stab, ast)
    print(cres)
    for k in cres:
        with open(k, "w") as fil:
            fil.write(str(cres[k]))
    



if __name__ == "__main__":
    main()
